/*
 * base_packet.h
 *
 *  Created on: 2014-4-24
 *      Author: lixingyi
 */

#ifndef BASE_PACKET_H_
#define BASE_PACKET_H_

#include <sstream>
#include <exception>
#include "packet.h"

using namespace kingnet ;

struct cs_head
{


    int32_t length ;
    int32_t reserved ;
    int32_t role_id ;
    int16_t option_length ;        //optional head length
    int16_t head_length ;
    int16_t msg_id ;
    int8_t type ;
    int32_t seq1 ;
    int32_t seq ;      //real seq

} __attribute__((packed)) ;


int decode_packet_size(const char* data,int size)
{
    if(size < 4 ) return -1 ;
    cs_head* head = (cs_head*)data ;
    return ntoh_int32(head->length);

}


int encode_head(cs_head* obj,char* data,int size)
{
    cs_head* head = (cs_head*)data ;
    head->length = hton_int32(obj->length);
    head->reserved = hton_int32(obj->reserved);
    head->role_id = hton_int32(obj->role_id);
    head->option_length = hton_int16(obj->option_length);
    head->head_length = hton_int16(obj->head_length);
    head->msg_id = hton_int16(obj->msg_id);
    head->type = (obj->type);
    head->seq1 = hton_int32(obj->seq1);
    head->seq = hton_int32(obj->seq);
    return sizeof(cs_head) ;
    
}

int decode_head(cs_head* obj,const char* data,int size)
{
    cs_head* head = (cs_head*)data ;
    obj->length = ntoh_int32(head->length);
    obj->reserved = ntoh_int32(head->reserved);
    obj->role_id = ntoh_int32(head->role_id);
    obj->option_length = ntoh_int16(head->option_length);
    obj->head_length = ntoh_int16(head->head_length);
    obj->msg_id = ntoh_int16(head->msg_id);
    obj->type = (head->type);
    obj->seq1 = ntoh_int32(head->seq1);
    obj->seq = ntoh_int32(head->seq);
    return sizeof(cs_head) ;
}




template<int32_t PT,typename BT>
class cs_packet : public kingnet::packet
{
public:
    enum{ packet_type = PT ,} ;
    typedef BT body_type ;
public:
    cs_packet()
    {
        memset(&head,0,sizeof(head));
        head.head_length = sizeof(head) ;
        head.msg_id = packet_type ;
        head.type = 0x1 ;
    }

    virtual int get_type() {return packet_type ; } ;

    virtual int encode(char* data,int size)
    {

        char* body_data = data + sizeof(cs_head) ;
        uint32_t offset = 0 ;
        if(body.Encode((uint8_t*)body_data,size-sizeof(cs_head),offset)<0)
        { 
            return -1 ;
        }
        
        head.length = head.head_length + offset ;
        //printf("encode msgid:%#x length:%d\n",head.msg_id,head.length) ;
        
        encode_head(&head,data,sizeof(cs_head)) ;
       

        return head.length ;

    }
    virtual int decode(const char* data,int size)
    {
        const char* body_data = data + sizeof(cs_head) ;
        uint32_t offset = 0 ;

        if(body.Decode((uint8_t*)body_data,size-sizeof(cs_head),offset)<0)
        { 
            return -1 ;
        }

        decode_head(&head,data,sizeof(cs_head));

        
        return head.length ;

    }

    virtual int encode_size()
    {
        int need_size = sizeof(cs_head) + sizeof(body)+1024 ;
        
        return need_size ;
    }

    virtual int decode_size(const char* data,int size)
    {
        return  decode_packet_size(data,size) ;

    }

public:
    cs_head head ;
    body_type body ;
};



#endif /* GAME_PACKET_H_ */
